package cn.edu.cuc.yjsy.admin.views;

import java.sql.SQLException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.emf.common.util.AbstractEnumerator;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.impl.EEnumImpl;
import org.eclipse.jface.action.ContributionItem;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.ViewPart;
import cn.edu.cuc.yjsy.admin.Activator;
import cn.edu.cuc.yjsy.admin.IDefaultConstants;
import cn.edu.cuc.yjsy.admin.connection.TargetConnection;
import cn.edu.cuc.yjsy.admin.controllers.StudentController;
import cn.edu.cuc.yjsy.admin.util.ColumnComparator;
import cn.edu.cuc.yjsy.admin.util.ILogger;
import cn.edu.cuc.yjsy.admin.util.LoggerAdvisor;
import cn.edu.cuc.yjsy.admin.util.MessageHelper;
import cn.edu.cuc.yjsy.admin.util.StudentAttributes;
import cn.edu.cuc.yjsy.admin.util.StudentComparator;
import cn.edu.cuc.yjsy.model.ModelPackage;
import cn.edu.cuc.yjsy.model.Student;

public class QueryResultView extends ViewPart {
	
	public final static String ID = "cn.edu.cuc.yjsy.admin.resultView";
	private Activator plugin;
	private Table table;
	private StatusContributionItem statusItem = null;

	private final static Map columnsWidth = new HashMap(ModelPackage.STUDENT_FEATURE_COUNT);
	private final static int[] columnsID = {ModelPackage.STUDENT__NUMBER, ModelPackage.STUDENT__NAME,
		ModelPackage.STUDENT__IDNUMBER, ModelPackage.STUDENT__MATRICULANDTYPE, 
		ModelPackage.STUDENT__GENDER, ModelPackage.STUDENT__NATIONALITY,
		ModelPackage.STUDENT__LENGTH, ModelPackage.STUDENT__LEVEL,
		ModelPackage.STUDENT__LEARNTYPE, ModelPackage.STUDENT__PROVINCE};
	
	private List result = null;
	private ColumnComparator comparator;
	
	private ILogger logger = new LoggerAdvisor(QueryResultView.class);
	
	static{			
		initialColumnWidth();
	}

	private static void initialColumnWidth() {
		columnsWidth.put(Integer.valueOf(ModelPackage.STUDENT__BIRTHDAY), Integer.valueOf(80));
		columnsWidth.put(Integer.valueOf(ModelPackage.STUDENT__COLLEGE), Integer.valueOf(100));
		columnsWidth.put(Integer.valueOf(ModelPackage.STUDENT__COLLEGECODE), Integer.valueOf(80));
		columnsWidth.put(Integer.valueOf(ModelPackage.STUDENT__DEPARTMENT), Integer.valueOf(80));
		columnsWidth.put(Integer.valueOf(ModelPackage.STUDENT__EXAMINENUMBER), Integer.valueOf(100));
		columnsWidth.put(Integer.valueOf(ModelPackage.STUDENT__DIPLOMACODE), Integer.valueOf(50));
		columnsWidth.put(Integer.valueOf(ModelPackage.STUDENT__GENDER), Integer.valueOf(40));
		columnsWidth.put(Integer.valueOf(ModelPackage.STUDENT__GRADE), Integer.valueOf(80));
		columnsWidth.put(Integer.valueOf(ModelPackage.STUDENT__GRADUATEDATE), Integer.valueOf(50));
		columnsWidth.put(Integer.valueOf(ModelPackage.STUDENT__IDNUMBER), Integer.valueOf(120));
		columnsWidth.put(Integer.valueOf(ModelPackage.STUDENT__LEARNTYPE), Integer.valueOf(80));
		columnsWidth.put(Integer.valueOf(ModelPackage.STUDENT__LENGTH), Integer.valueOf(50));
		columnsWidth.put(Integer.valueOf(ModelPackage.STUDENT__LEVEL), Integer.valueOf(80));
		columnsWidth.put(Integer.valueOf(ModelPackage.STUDENT__MATRICULANDTYPE), Integer.valueOf(80));
		columnsWidth.put(Integer.valueOf(ModelPackage.STUDENT__NAME), Integer.valueOf(60));
		columnsWidth.put(Integer.valueOf(ModelPackage.STUDENT__NATIONALITY), Integer.valueOf(40));
		columnsWidth.put(Integer.valueOf(ModelPackage.STUDENT__NUMBER), Integer.valueOf(100));
		columnsWidth.put(Integer.valueOf(ModelPackage.STUDENT__PROVINCE), Integer.valueOf(120));
		columnsWidth.put(Integer.valueOf(ModelPackage.STUDENT__REGISTERDATE), Integer.valueOf(80));
		columnsWidth.put(Integer.valueOf(ModelPackage.STUDENT__RESULT), Integer.valueOf(50));
		columnsWidth.put(Integer.valueOf(ModelPackage.STUDENT__SPECIALITYCODE), Integer.valueOf(80));
		columnsWidth.put(Integer.valueOf(ModelPackage.STUDENT__SPECIALITYNAME), Integer.valueOf(120));
		columnsWidth.put(Integer.valueOf(ModelPackage.STUDENT__UNITNAME), Integer.valueOf(200));
		columnsWidth.put(Integer.valueOf(ModelPackage.STUDENT__UNITPROVINCE), Integer.valueOf(100));
	}

	public QueryResultView() {
		this.plugin = Activator.getDefault();
		comparator = new StudentComparator();
		comparator.setColumn(ModelPackage.STUDENT__NUMBER);
	}

	public void createPartControl(Composite parent) {
		parent.setLayout(new FillLayout());
		table = new Table(parent, SWT.BORDER | SWT.MULTI | 
				SWT.V_SCROLL | SWT.H_SCROLL | SWT.FULL_SELECTION);
		table.setHeaderVisible(true);
		table.setLinesVisible(true);
		
		for (int i = 0; i < columnsID.length; i++) {
			int index = columnsID[i];
			TableColumn column = new TableColumn(table, SWT.NONE);
		    column.setText(plugin.getResourceString2(StudentAttributes.getColumnName(index)));
		    column.addSelectionListener(new TableSelectionAadapter(index));
			column.pack();
			column.setMoveable(true);
			column.setWidth(getColumnWidth(index));
		}
//	    for (int i = 0; i < table.getColumnCount(); i++) {
//
//		}
	    
	    table.addMouseListener(new MouseAdapter(){
	    	public void mouseDoubleClick(MouseEvent e) {
				try {
		    		TableItem item = table.getItem(new Point(e.x, e.y));
		    		int index = table.getTopIndex();
		    		boolean bFound = false;
		    		while(index < table.getItemCount()){
		    			item = table.getItem(index);
		    			for (int i = 0; i < table.getColumnCount(); i++) {
		    	            Rectangle rect = item.getBounds(i);
		    	            if(rect.contains(e.x, e.y)){
		    	            	bFound = true;
		    	            	break;
		    	            }
		    			}
		    			if(bFound)
		    				break;
		    			index++;
		    			item = null;
		    		}
		    		if(item == null)
		    			return;
					IViewPart part = getViewSite().getPage().showView(DetailView.ID,
							String.valueOf(System.currentTimeMillis()), IWorkbenchPage.VIEW_ACTIVATE);
					((DetailView)part).setDetail((Student)item.getData("data"));
				} catch (PartInitException e1) {
					logger.error("Error to open detail view");
					e1.printStackTrace();
				}
	    	}
	    });

	    setPartName(plugin.getResourceString2("str.view.result.title.label"));
	}
	
	public int getColumnWidth(int key){
		if(columnsWidth.containsKey(new Integer(key)))
			return ((Integer)columnsWidth.get(new Integer(key))).intValue();
		else
			return 50;
	}

	public void setFocus() {
		// TODO Auto-generated method stub

	}
	
	private void updateStatusLine() {
		String statusText = NLS.bind(MessageHelper.STATUS_QUERYRECORD_NUMBER, Integer.valueOf(result.size()));
		if(statusItem == null){
			statusItem = new StatusContributionItem(statusText);
			IStatusLineManager statusLine = getViewSite().getActionBars().getStatusLineManager();
			statusLine.insertAfter(IDefaultConstants.STATUS_GROUP1, statusItem);
			statusLine.update(true);
		}else
			statusItem.setLabelText(statusText);
	}
	
	private void fillTable() {
		// Turn off drawing to avoid flicker
		table.setRedraw(false);

		// We remove all the table entries, sort our
		// rows, then add the entries
		table.removeAll();
		if(result != null){
			try{
				Collections.sort(result, comparator);
			
				for(Iterator iter = result.iterator(); iter.hasNext();){
					Student s = (Student)iter.next();					
					TableItem item = new TableItem(table, SWT.NONE);
					item.setData("data", s);
					
					for(int i = 0; i < columnsID.length; i++){
						int index = columnsID[i];
						EStructuralFeature feature = 
							ModelPackage.eINSTANCE.getStudent().getEStructuralFeature(index);
						String typeName = feature.getEType().getName();
						String value = null;
						if(s.eGet(feature) != null){
							if(typeName.equals("EString"))
								value = (String)s.eGet(feature);
							else if(feature.getEType() instanceof EEnumImpl)
								value = ((AbstractEnumerator)s.eGet(feature)).getLiteral();
							else
								value = s.eGet(feature).toString();
							
							if(value != null)
								item.setText(i, value);								
						}		
					}
				}
			}catch(Exception e){
				e.printStackTrace();
			}
		}
		// Turn drawing back on
		table.setRedraw(true);
		
		
	}

	public void doQuery(final Map inputs){
		Job queryJob = new Job("Query students..."){
			protected IStatus run(IProgressMonitor monitor) {	
				StudentController controller = new StudentController();
				try {
					result = controller.query(TargetConnection.getInstance(), inputs);
				} catch (SQLException e) {
					logger.error("Error in query: " + inputs);
					e.printStackTrace();
				}
				Display.getDefault().syncExec(new Runnable(){
					public void run() {	
						fillTable();
						updateStatusLine();
					}
				});
				return Status.OK_STATUS;
			}};
		queryJob.addJobChangeListener(new JobChangeAdapter(){
			Shell progress;
			
			public void aboutToRun(IJobChangeEvent event) {
				Display.getDefault().syncExec(new Runnable(){
					public void run() {
						Shell window = getSite().getShell();
						progress = new Shell(window, SWT.TOOL);
						progress.setLayout(new FillLayout(SWT.VERTICAL));
						Label l = new Label(progress, SWT.BORDER | SWT.HORIZONTAL 
								| SWT.VERTICAL | SWT.CENTER);
						l.setForeground(Display.getDefault()
								.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
						l.setBackground(window.getDisplay()
								.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
						l.setText(plugin.getResourceString2("str.query.progress.label"));
						l.setFont(new Font(Display.getDefault(), "Times New Roman", 12, SWT.BOLD));
						Rectangle rect = table.getBounds();
						Point pt = table.toDisplay(rect.x + rect.width/3, 
								rect.y + rect.height/3);
						progress.setBounds(pt.x, pt.y, 150, 100);
						progress.setVisible(true);
					}					
				});
			}
			public void done(IJobChangeEvent event) {
				Display.getDefault().syncExec(new Runnable(){
					public void run() {
						if(progress != null)
							progress.dispose();
					}
				});				
			}
		});
		queryJob.setSystem(true);
		queryJob.schedule();
	}
	
	private class TableSelectionAadapter extends SelectionAdapter{
		int index;
		
		public TableSelectionAadapter(int idx){
			this.index = idx;
		}
		
		public void widgetSelected(SelectionEvent event) {
			comparator.setColumn(index);
			comparator.reverseDirection();
			fillTable();
		}
	}
	
	private class StatusContributionItem extends ContributionItem{
		
		private CLabel label;
		private String statusText;
		
		public StatusContributionItem(String text){
			statusText = text;
		}
		/**
		 * Creates a status line consisting of a label which is used to hold an icon and a combo box
		 *
		 * @see IContributionItem#fill(Composite)
		 */
		public void fill(Composite parent) {
			Composite c = new Composite(parent,0);
			label = new CLabel(c, SWT.RIGHT);
			label.setSize(300, 20);
			label.setText(statusText);		
		}
		
		public void setLabelText(String string) {
			label.setText(string);
			statusText = string;
		}
	}
}
